#include "Basic/Basic.h"
#include "Basic/String.h"
#include "Basic/Pointer.h"
#include "Basic/UnitTest.h"
using namespace zl;


namespace ObjectTestAutoPtr
{
	class Base :public Object
	{
	public:
		zint num;
	public:
		Base(zint _num) :num(_num)
		{

		}
	};
	class Device1 :public Base
	{
	public:
		Device1(zint _num) :Base(_num)
		{}
	};
	class Device2 :public Base
	{
	public:
		Device2(zint _num) :Base(_num)
		{}
	};

	template <typename T>
	class P :public Object
	{
	public:
		T num;
	public:
		P(T _num){ num = _num; }
	};
};

using namespace ObjectTestAutoPtr;

TEST_CASE(TestAutoPtr)
{
	Base* p1 = new Base(1);
	Base* p2 = new Device1(2);
	Base* p3 = new Device2(3);

	Base* p[] = { p1, p2, p3 };
	Ptr<Base>ps[] = { p1, p2, p3 };

	Ptr<P<zint> > pk = new P<zint>(33);
	assert(pk->num == 33);

	for (zint i = 0; i < sizeof(ps) / sizeof(*ps); i++)
	{
		assert(ps[i].Obj() == p[i]);
		assert(ps[i]->num == p[i]->num);
		assert((bool)ps[i] == true);
	}

	for (zint i = 0; i<sizeof(ps) / sizeof(*ps); i++)
	{
		for (zint j = 0; j<sizeof(ps) / sizeof(*ps); j++)
		{
			assert(((ps[i] == ps[j]) == (p[i] == p[j])));
			assert(((ps[i] != ps[j]) == (p[i] != p[j])));
			assert(((ps[i] >= ps[j]) == (p[i] >= p[j])));
			assert(((ps[i]>ps[j]) == (p[i]>p[j])));
			assert(((ps[i] <= ps[j]) == (p[i] <= p[j])));
			assert(((ps[i]<ps[j]) == (p[i]<p[j])));

			assert(((ps[i] == p[j]) == (p[i] == p[j])));
			assert(((ps[i] != p[j]) == (p[i] != p[j])));
			assert(((ps[i] >= p[j]) == (p[i] >= p[j])));
			assert(((ps[i]>p[j]) == (p[i]>p[j])));
			assert(((ps[i] <= p[j]) == (p[i] <= p[j])));
			assert(((ps[i]<p[j]) == (p[i]<p[j])));
		}
	}

	Ptr<Device1> ptr1 = ps[1].Cast<Device1>();
	Ptr<Device2> ptr2 = ps[1].Cast<Device2>();

	assert(((bool)ptr1 == true));
	assert((ptr1->num == 2));
	assert(((bool)ptr2 == false));

	ptr1 = ps[2].Cast<Device1>();
	ptr2 = ps[2].Cast<Device2>();
	assert(((bool)ptr1 == false));
	assert((ptr2->num == 3));
	assert(((bool)ptr2 == true));

	ptr1 = ps[0].Cast<Device1>();
	ptr2 = ps[0].Cast<Device2>();
	assert(((bool)ptr1 == false));
	assert(((bool)ptr2 == false));
	{
		Base* p5 = new Base(7);
		Base* p7 = new Device1(30);
		Base* p9 = new Device2(30);
		Device1* p6 = dynamic_cast<Device1*>(p5);
		Device1* p8 = dynamic_cast<Device1*>(p7);
		Device1* p10 = dynamic_cast<Device1*>(p9);
		Base*    p11 = dynamic_cast<Base*>(p9);
		assert((!p6));
		assert((p8));
		assert((!p10));
		assert(p11);
		delete p5;
		delete p7;
		delete p9;
	}
	ptr1 = new Device1(1);
	ptr2 = new Device2(2);
	Ptr<Base> ptr3 = new Device1(10);
	Ptr<Base> ptr4 = new Base(20);
	Ptr<Device1> ptr5 = new Device1(10);
	assert(((bool)ptr1 == true));
	assert(((bool)ptr2 == true));
	assert(((bool)ptr3 == true));
	ptr4 = ptr5;
	assert(((bool)ptr4 == true));
	assert((ptr4->num == 10));
	ptr3 = ptr4;
	assert(((bool)ptr3 == true));
	assert((ptr3->num == 10));

	char i = -128;
	char j = -i;
	assert(j == -128);
}
